//实现的基本思想
//生产者最关心的资源是什么?
//是环形队列中空的位置

//消费者最关心的资源是什么?
//是环形队列中的存在的数据

//实现规则
//1.生产者不能把消费者超过一个圈
//2.消费者不能超过生产者
//3.当指向同一个位置的时候,需要根据空,满的状态来判断让那个优先执行
//4.生产和消费可以并发执行

#pragma once 

#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

namespace qds 
{
    const int defalut_capacity = 5;
    
    template <class T>
    class ring_queue 
    {
    public:
        ring_queue(int capacity = defalut_capacity)
        :_ring_queue(capacity)
         ,_capacity(capacity)
        {
            sem_init(&_blank_sem, 0, capacity);
            sem_init(&_data_sem, 0, 0);

            _consumer_position = _producer_position = 0;

            pthread_mutex_init(&_consumer_mutex, nullptr);
            pthread_mutex_init(&_producer_mutex, nullptr);
        }

        ~ring_queue()
        {
            sem_destroy(&_blank_sem);
            sem_destroy(&_data_sem);

            pthread_mutex_destroy(&_consumer_mutex);
            pthread_mutex_destroy(&_producer_mutex);
        }

        //多生产者和多消费者的优势不是这里,而是可以并发的获取和处理任务
        //生产接口
        void push(const T& in)
        {
            //pthread_mutex_lock(&_producer_mutex);
            //这里进行上锁的操作也是可以的,不过效率不行,因为只有一个线程进行信号量的申请,然后进行生产
            
            //进行P操作,
            sem_wait(&_blank_sem);

            //这里进行上锁,一个线程信号量申请的同时,那么一个线程可以进行生产,如果
            pthread_mutex_lock(&_producer_mutex);

            //信号量申请到了,开始进行生产
            _ring_queue[_producer_position] = in;

            _producer_position++;
            _producer_position %= _capacity;

            pthread_mutex_unlock(&_producer_mutex);

            //进行V操作
            sem_post(&_data_sem);
        }

        //消费接口
        void pop(T* out)
        {
            //进行P操作
            sem_wait(&_data_sem);

            pthread_mutex_lock(&_consumer_mutex);

            *out = _ring_queue[_consumer_position];

            _consumer_position++;
            _consumer_position %= _capacity;

            pthread_mutex_unlock(&_consumer_mutex);

            //进行V操作
            sem_post(&_blank_sem);
        }

    private:
        std::vector<T> _ring_queue;

        int _capacity;

        //生产者关心的有空资源
        sem_t _blank_sem; 

        //消费者关心的已有数据资源
        sem_t _data_sem;

        //生产者和消费者在循环队列中的位置
        int _consumer_position;
        int _producer_position;

        //多个生产者和消费者需要保持互斥的关系,所以需要互斥量
        pthread_mutex_t _consumer_mutex;
        pthread_mutex_t _producer_mutex;
    };
}
